package com.jh.jswitch;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.DrawableWrapper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScrollCaptureTarget;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.CompoundButton;
import android.widget.Switch;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;

import java.util.function.Consumer;

public class CustomSwitch extends Switch {
    public static final String TAG = "CustomSwitch";

    Paint mPaint;
    Path mPath;

    public CustomSwitch(Context context) {
        super(context);
        init();
    }

    public CustomSwitch(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init(){
        mPaint = new Paint();
        mPaint.setColor(getResources().getColor(R.color.white_500, null));
        mPaint.setShadowLayer(5f, 0, 3, Color.GRAY);
        mPath = new Path();

        setMinHeight(dp2px(40));
        setSwitchMinWidth(dp2px(80));
        setElevation(10f);
    }

    public int dp2px(int dp){
        return (int) (1.0f*dp*getResources().getDisplayMetrics().density + 0.5f);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        setThumbDrawable(null);
        setBackground(getResources().getDrawable(R.drawable.switch_round_bg, null));
        setTrackDrawable(getResources().getDrawable(R.drawable.switch_track, null));

        mPath.reset();
        mPath.addCircle((1.0f*getHeight()/4) * 2, 1.0f*getHeight()/2, 1.0f*getHeight()/4, Path.Direction.CCW);

        ValueAnimator valueAnimator = ValueAnimator.ofArgb(ContextCompat.getColor(getContext(), R.color.white_500), ContextCompat.getColor(getContext(), R.color.white));
        valueAnimator.setDuration(250);
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(@NonNull ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                setThumbTintList(ColorStateList.valueOf(animatedValue));
            }
        });

        ValueAnimator valueAnimatorBg = ValueAnimator.ofArgb(ContextCompat.getColor(getContext(), R.color.white_200), ContextCompat.getColor(getContext(), R.color.white_select));
        valueAnimatorBg.setDuration(500);
        valueAnimatorBg.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimatorBg.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(@NonNull ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                setBackgroundTintList(ColorStateList.valueOf(animatedValue));
            }
        });

        ValueAnimator valueAnimatorTrack = ValueAnimator.ofArgb(ContextCompat.getColor(getContext(), R.color.white_500), ContextCompat.getColor(getContext(), R.color.white_select));
        valueAnimatorTrack.setDuration(250);
        valueAnimatorTrack.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimatorTrack.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(@NonNull ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                setTrackTintList(ColorStateList.valueOf(animatedValue));
            }
        });

        ValueAnimator valueAnimatorThumbColor = ValueAnimator.ofArgb(ContextCompat.getColor(getContext(), R.color.white_500), ContextCompat.getColor(getContext(), R.color.white));
        valueAnimatorThumbColor.setDuration(250);
        valueAnimatorThumbColor.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimatorThumbColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(@NonNull ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                mPaint.setColor(animatedValue);
                invalidate();
            }
        });

        ValueAnimator valueAnimatorThumb= ValueAnimator.ofFloat((1.0f*getHeight()/4)*2 , (getWidth() - (1.0f*getHeight()/2)));
        valueAnimatorThumb.setDuration(500);
        valueAnimatorThumb.setInterpolator(new OvershootInterpolator());
        valueAnimatorThumb.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(@NonNull ValueAnimator animation) {
                float animatedValue = (float) animation.getAnimatedValue();
                mPath.reset();
                mPath.addCircle(animatedValue, 1.0f*getHeight()/2, 1.0f*getHeight()/4, Path.Direction.CCW);
            }
        });

        ValueAnimator valueAnimatorThumbL = ValueAnimator.ofFloat((getWidth() - (1.0f*getHeight()/2)), (1.0f*getHeight()/4)*2);
        valueAnimatorThumbL.setDuration(500);
        valueAnimatorThumbL.setInterpolator(new OvershootInterpolator());
        valueAnimatorThumbL.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(@NonNull ValueAnimator animation) {
                float animatedValue = (float) animation.getAnimatedValue();
                mPath.reset();
                mPath.addCircle(animatedValue, 1.0f*getHeight()/2, 1.0f*getHeight()/4, Path.Direction.CCW);
            }
        });

        setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.d(TAG, "onCheckedChanged: ");
                if (!isChecked){
                    valueAnimator.reverse();
                    valueAnimatorBg.reverse();
                    valueAnimatorTrack.reverse();
                    valueAnimatorThumbL.start();
                    valueAnimatorThumbColor.reverse();
                }else{
                    valueAnimator.start();
                    valueAnimatorBg.start();
                    valueAnimatorTrack.start();
                    valueAnimatorThumb.start();
                    valueAnimatorThumbColor.start();
                }
                invalidate();
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                break;
            default:
                break;
        }
        return super.onTouchEvent(ev);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable trackDrawable = getTrackDrawable();
        trackDrawable.setBounds((int) (1.0f*getWidth() / 3), (int) (1.0f*getHeight() / 21 * 10), (int) (1.0f*getWidth() / 3 * 2), (int) (1.0f*getHeight() / 21 * 11));
        super.onDraw(canvas);

        int i = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint);
        canvas.drawPath(mPath, mPaint);
    }
}
